using System;
using System.Drawing;
using ArcEngine;
using ArcEngine.Audio;
using ArcEngine.Graphics;
using ArcEngine.Input;
//using ArcEngine.Network;
using ArcEngine.Resources;
using ArcEngine.Time;
using System.Windows.Forms;

//
//http://gamedevgeek.com/tutorials/managing-game-states-in-c/
//
// Physic Engine :
// - http://www.box2d.org/
// - chipmunk http://www.codeplex.com/chipmunkxna
// - http://www.codeplex.com/FarseerPhysics/
// - http://www.codeplex.com/FarseerPhysics
//
// Gestionnaire d'evenements
// - http://www.ziggyware.com/readarticle.php?article_id=101
//
//
// GUI:
// - http://www.codeplex.com/neoforce
//
// Text :
// - http://www.createdbyx.com/id-Code+Snips__DrawString+method+with+word+wrap+and+text+alignment-XNA.aspx
//
//
//
//


namespace RuffnTumble
{

	/// <summary>
	/// This is the main type for your game
	/// </summary>
	public class Ruff
	{
		/// <summary>
		/// 
		/// </summary>
		/// <param name="args"></param>
		[STAThread]
		static void Main(string [] args)
		{
			Ruff game = new Ruff();
			game.Init();
			Video.Run();
		}



		/// <summary>
		/// Allows the game to perform any initialization it needs to before starting to run.
		/// This is where it can query for any required services and load any non-graphic
		/// related content.  Calling base.Initialize will enumerate through any components
		/// and initialize them as well.
		/// </summary>
		protected void Init()
		{
			Video.Init();

			// Events 
			Keyboard.OnKeyDown += new EventHandler<PreviewKeyDownEventArgs>(OnKeyDown);
			Video.OnClosing += new EventHandler<QuitEventArgs>(OnClosing);
			Video.OnFrameTick += new EventHandler<FrameTickArgs>(OnFrameTick);
			Terminal.OnProcessCommand += new ProcessCommand(ProcessConsoleCommands);

			// Enble the console
			Terminal.Enable = true;

			// Loads content
			ResourceManager.LoadBank("data/world1.bnk");

			// Init display
			Video.OpenRender(new Size(800, 600), false);
			Video.WindowCaption = "Ruff'n'Tumble";
			Video.Blending = true;


			// Sets the level
			ResourceManager.CurrentLevel = ResourceManager.GetLevel("Level1_1");
			ResourceManager.CurrentLevel.Init();
			ResourceManager.DisplayZone = new Rectangle(0, 56, 800, 544);


			// Default rendering font
			Video.Font = ResourceManager.GetTTFFont("Verdana");
		}



		/// <summary>
		/// Process command entered in the terminal
		/// </summary>
		/// <param name="text"></param>
		void ProcessConsoleCommands(string cmd)
		{
			Console.WriteLine(cmd);
		}




		/// <summary>
		/// Allows the game to run logic such as updating the world,
		/// checking for collisions, gathering input, and playing audio.
		/// </summary>
		protected void Update()
		{
			Level level = ResourceManager.CurrentLevel;
			if (level == null)
				return;


			level.Update();



			// Center the collision layer to match the location on the screen
			Layer layer = ResourceManager.CurrentLevel.GetLayer("tiles");
			if (layer != null)
			{
				// Center the player in the middle of the screen
				Entity player = layer.GetEntity("Player");
				if (player != null)
				{
					// Level layer
					level.Location = new Point(
							(int) (player.Location.X - ResourceManager.DisplayZone.Width / 2.0f),
							(int) (player.Location.Y - ResourceManager.DisplayZone.Height / 2.0f));

				}

			}
		}


		/// <summary>
		/// This is called when the game should draw itself.
		/// </summary>
		protected void Render()
		{
			// Clears the background
			Video.ClearBuffers();

			Level level = ResourceManager.CurrentLevel;
			if (level == null)
				return;


			// Draw the level
			level.Draw();



			// Draw the status bar
			TileSet icon = ResourceManager.GetTileSet("Layout");
			if (icon != null)
			{
				icon.Draw(0, Point.Empty);
			}




			#region Stats
			Point pos = Point.Empty;
			Layer layer = level.GetLayer("tiles");
			Entity player = level.GetLayer("tiles").GetEntity("Player");
			if (player.God)
				Video.DrawText(new Point(700, 60), "GOD MODE !!!!");



			if (DebugStat)
			{



				Video.Color = Color.White;
				Rectangle rect = player.CollisionBoxLocation;
				rect.Location = level.LevelToScreen(rect.Location);
				Video.Rectangle(rect, false);

				Point tl = new Point(player.CollisionBoxLocation.Left, player.CollisionBoxLocation.Top);
				Point tr = new Point(player.CollisionBoxLocation.Left + player.CollisionBoxLocation.Width, player.CollisionBoxLocation.Top);
				Point bl = new Point(tl.X, tl.Y + player.CollisionBoxLocation.Height);
				Point br = new Point(tr.X, bl.Y);

				Video.Color = Color.White;
				Layer col = ResourceManager.CurrentLevel.CollisionLayer;
				Video.DrawText(new Point(400, 100), "tl : " + tl.ToString() + " = " + col.GetTileAtCoord(tl));
				Video.DrawText(new Point(400, 120), "tr : " + tr.ToString() + " = " + col.GetTileAtCoord(tr));
				Video.DrawText(new Point(400, 140), "bl : " + bl.ToString() + " = " + col.GetTileAtCoord(bl));
				Video.DrawText(new Point(400, 160), "br : " + br.ToString() + " = " + col.GetTileAtCoord(br));


				string txt;
				pos = new Point(100, 70);
				txt = "Level name : \"" + ResourceManager.CurrentLevel.Name + "\"";
				Video.DrawText(pos, txt);
				Point lvlpos = level.Location;

				txt = "Level pos : " + lvlpos.X + "x" + lvlpos.Y;
				pos.Y += Video.Font.LineHeight;
				Video.DrawText(pos, txt);


				if (player != null)
				{
					txt = "Player pos : " + player.Location.X + "x" + player.Location.Y;
					pos.Y += Video.Font.LineHeight;
					Video.DrawText(pos, txt);
				}



				pos = new Point(10, 200);
				pos.Y += Video.Font.LineHeight;
				Video.DrawText(pos, GameTime.Elapsed.ToString());

				pos.Y += Video.Font.LineHeight;
				Video.DrawText(pos, "Jumping : " + player.IsJumping + " - " + player.Jump);
				pos.Y += Video.Font.LineHeight;
				Video.DrawText(pos, "Falling : " + player.IsFalling + "   ");

				pos = new Point(10, 550);
				txt = "Press 'C' to shows/hides collision layer, 'G' to shows/hides grid, 'W' for god mode";
				Video.DrawText(pos, txt);
				txt = "Press F1 to F5 to change level, 'Escape' to quit";
				pos.Y += Video.Font.LineHeight;
				Video.DrawText(pos, txt);
			}


			// Hot spot
			Video.Color = Color.Red;
			Point off = level.LevelToScreen(player.Location);
			Video.Plot(off);
			Video.Color = Color.White;

			#endregion







			// Swap buffers
			Video.SwapBuffers();

		}



		#region Events

		/// <summary>
		/// Fires every frame. 
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>
		void OnFrameTick(object sender, FrameTickArgs e)
		{
			Update();
			Render();
		}



		/// <summary>
		/// Quits the application
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>
		void OnClosing(object sender, QuitEventArgs e)
		{
			ResourceManager.Clear();
		}




		/// <summary>
		/// On key down
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="evt"></param>
		void OnKeyDown(object sender, PreviewKeyDownEventArgs evt)
		{
			switch (evt.KeyCode)
			{
				// Byebye
				case Keys.Escape:
				{
					Console.WriteLine("Quit !!!!");
					Video.Quit();
				}
				break;

				// The player is like a god
				case Keys.W:
				{
					Layer layer = ResourceManager.CurrentLevel.GetLayer("tiles");
					if (layer == null)
						break;

					Entity player = layer.GetEntity("Player");
					if (player == null)
						break;

					player.God = !player.God;

				}
				break;

				// Display grid
				case Keys.G:
				{
					foreach (Layer layer in ResourceManager.CurrentLevel.Layers)
					{
						layer.ShowGrid = !layer.ShowGrid;
					}
				}
				break;


				case Keys.F11:
				{
					Video.WaitVbl = !Video.WaitVbl;
				}
				break;

				// 
				case Keys.F12:
				{
					Layer layer = ResourceManager.CurrentLevel.GetLayer("tiles");
					if (layer == null)
						break;

					Entity player = layer.GetEntity("Player");
					if (player == null)
						break;

					player.Location = layer.GetSpawnPoint("player1").Location;
				}
				break;


				// Shows some debug
				case Keys.Insert:
				{
					DebugStat = !DebugStat;
				}
				break;

				// Shows collision layer
				case Keys.C:
				{
					Layer layer = ResourceManager.CurrentLevel.GetLayer("collision");
					if (layer != null)
						layer.Visible = !ResourceManager.CurrentLevel.GetLayer("collision").Visible;
				}
				break;

				// Change to level 1_1 => 1_5
				case Keys.F1:
				{
					ResourceManager.CurrentLevel = ResourceManager.GetLevel("Level1_1");
					ResourceManager.CurrentLevel.Init();
				}
				break;
				case Keys.F2:
				{
					ResourceManager.CurrentLevel = ResourceManager.GetLevel("Level1_2");
					ResourceManager.CurrentLevel.Init();
				}
				break;
				case Keys.F3:
				{
					ResourceManager.CurrentLevel = ResourceManager.GetLevel("Level1_3");
					ResourceManager.CurrentLevel.Init();
				}
				break;
				case Keys.F4:
				{
					ResourceManager.CurrentLevel = ResourceManager.GetLevel("Level1_4");
					ResourceManager.CurrentLevel.Init();
				}
				break;
				case Keys.F5:
				{
					ResourceManager.CurrentLevel = ResourceManager.GetLevel("Level1_5");
					ResourceManager.CurrentLevel.Init();
				}
				break;


			}
		}



		#endregion


		#region Properties


		/// <summary>
		/// Shows/Hides debug stats
		/// </summary>
		bool DebugStat;

		#endregion
	}
}
